package com.hxl.tech.gateway.auth.oauth;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.hxl.tech.gateway.auth.config.OpenApiConfig;
import com.hxl.tech.gateway.auth.dto.limitrule.LimitIpDTO;
import com.hxl.tech.gateway.auth.exception.AuthException;
import com.hxl.tech.gateway.auth.model.Application;
import com.hxl.tech.gateway.auth.service.ApplicationService;
import com.hxl.tech.gateway.auth.util.RestTemplateUtil;
import com.hxl.tech.gateway.common.constant.AppConstant;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpMethod;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * 用户认证实现
 * @author soliddq
 * @date 2023-10-14
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class UserAuthService implements UserDetailsService {

    private final PasswordEncoder passwordEncoder;
    private final ApplicationService applicationService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        HttpServletRequest servletRequest = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        String merchantCode = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest().getParameter("merchant_code");
        String phone = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest().getParameter("phone");
        String password = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest().getParameter("password");

        if (servletRequest.getRequestURI().contains("/login")) {
            // 授权码模式
            log.info("商户号:[{}],手机:[{}] OAuth授权码模式远程登录中...", merchantCode, phone);
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("merchant_code", merchantCode);
            jsonObject.put("phone", phone);
            jsonObject.put("password", password);

            String loginUrl = OpenApiConfig.getOpenLoginUrl();
            String loginPath = OpenApiConfig.getOpenLoginPath();
            Object obj = RestTemplateUtil.send(loginUrl+loginPath, HttpMethod.POST, JSONObject.toJSONString(jsonObject));
            OAuthUserResponse response = JSON.parseObject(JSON.toJSONString(obj), new TypeReference<OAuthUserResponse>() {});
            if (response.getCode() != 200) {
                throw new AuthException(response.getMsg());
            }

            OAuthUser oAuthUser = response.getData();
            if (StringUtils.isBlank(oAuthUser.getMerchantCode())) {
                throw new AuthException("商户号不能为空");
            }
            oAuthUser.setPassword(passwordEncoder.encode(password));
            oAuthUser.setAuthorities(Arrays.asList(AppConstant.ROLE_OPEN_DEV_CODE));
            log.info("商户号:[{}],手机:[{}] OAuth授权码模式远程登录成功", merchantCode, phone);
            return oAuthUser;
        }  else if (servletRequest.getRequestURI().contains("/oauth/token")) {
            // 刷新token模式
            String grantType = servletRequest.getParameter("grant_type");
            String appId = ((org.springframework.security.core.userdetails.User) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername();
            Application application = applicationService.readForOAuth(appId);
            if (Objects.isNull(application) || application.getState() != AppConstant.StateEnum.ENABLE) {
                throw new AuthException("应用不存在或应用状态未启用");
            }
            if ("refresh_token".equals(grantType)) {
                OAuthUser oAuthUser = new OAuthUser();
                oAuthUser.setUsername(username);
                oAuthUser.setAuthorities(getAuthorities(application.getAppType()));
                return oAuthUser;
            } else {
                throw new AuthException("不支持的授权方式");
            }
        } else {
            throw new AuthException("不支持的URL");
        }
    }

    private List<String> getAuthorities(String appType) {
        List<String> authorities = new ArrayList<>(1);
        switch (appType) {
            case AppConstant.APP_TYPE_SYSTEM:
                authorities.add(AppConstant.ROLE_OPEN_SYSTEM_CODE);
                break;
            case AppConstant.APP_TYPE_DEV:
                authorities.add(AppConstant.ROLE_OPEN_DEV_CODE);
                break;
            default:
                authorities.add(AppConstant.ROLE_OPEN_INVALID_CODE);
                break;
        }
        return authorities;
    }
}